from numbers import Number
from typing import Literal, Union, Dict, List

from modules.amis.component.base import BaseSchema, Api, Action, SchemaMessage, OrderDir, \
    OnEvent, SchemaExpression, Remark, Badge, SchemaUrlPath, SchemaTpl, SchemaClassName, Renderable, SchemaNode, Theme, \
    SchemaCollection, SchemaName, SchemaApi, SchemaFunction
from modules.amis.component.datainput import Form


class Crud(BaseSchema):
    """
    CRUD，即增删改查组件，主要用来展现数据列表，并支持各类【增】【删】【改】【查】等操作。

    注意 CRUD 所需的数据必须放 items 中，因此如果只是想显示表格类型的数据没有分页，请使用 Table。

    Args:
        type:	string		type 指定为 CRUD 渲染器
        mode:	string	"table"	"table" 、 "cards" 或者 "list"
        title:	string	""	可设置成空，当设置成空时，没有标题栏
        className:	string		表格外层 Dom 的类名
        api:	API		CRUD 用来获取列表数据的 api。
        deferApi:	API		当行数据中有 defer 属性时，用此接口进一步加载内容
        loadDataOnce:	boolean		是否一次性加载所有数据（前端分页）
        loadDataOnceFetchOnFilter:	boolean	true	在开启 loadDataOnce 时，filter 时是否去重新请求 api
        source:	string		数据映射接口返回某字段的值，不设置会默认使用接口返回的${items}或者${rows}，也可以设置成上层数据源的内容
        filter:	Form		设置过滤器，当该表单提交后，会把数据带给当前 mode 刷新列表。
        filterTogglable:	boolean | {label: string; icon: string; activeLabel: string; activeIcon?: stirng;}	false	是否可显隐过滤器
        filterDefaultVisible:	boolean	true	设置过滤器默认是否可见。
        initFetch:	boolean	true	是否初始化的时候拉取数据, 只针对有 filter 的情况, 没有 filter 初始都会拉取数据
        interval:	number	3000	刷新时间(最低 1000)
        silentPolling:	boolean	false	配置刷新时是否隐藏加载动画
        stopAutoRefreshWhen:	string	""	通过表达式来配置停止刷新的条件
        stopAutoRefreshWhenModalIsOpen:	boolean	false	当有弹框时关闭自动刷新，关闭弹框又恢复
        syncLocation:	boolean	true	是否将过滤条件的参数同步到地址栏
        draggable:	boolean	false	是否可通过拖拽排序
        resizable:	boolean	true	是否可以调整列宽度
        itemDraggableOn:	boolean		用表达式来配置是否可拖拽排序
        saveOrderApi:	API		保存排序的 api。
        quickSaveApi:	API		快速编辑后用来批量保存的 API。
        quickSaveItemApi:	API		快速编辑配置成及时保存时使用的 API。
        bulkActions:	Array<Action>		批量操作列表，配置后，表格可进行选中操作。
        messages:	Object		覆盖消息提示，如果不指定，将采用 api 返回的 message
        messages.fetchFailed:	string		获取失败时提示
        messages.saveOrderFailed:	string		保存顺序失败提示
        messages.saveOrderSuccess:	string		保存顺序成功提示
        messages.quickSaveFailed:	string		快速保存失败提示
        messages.quickSaveSuccess:	string		快速保存成功提示
        primaryField:	string	"id"	设置 ID 字段名。
        perPage:	number	10	设置一页显示多少条数据。
        orderBy:	string		默认排序字段，这个是传给后端，需要后端接口实现
        orderDir:	asc | desc		排序方向
        defaultParams:	Object		设置默认 filter 默认参数，会在查询的时候一起发给后端
        pageField:	string	"page"	设置分页页码字段名。
        perPageField:	string	"perPage"	设置分页一页显示的多少条数据的字段名。注意：最好与 defaultParams 一起使用，请看下面例子。
        pageDirectionField:	string	"pageDir"	分页方向字段名可能是 forward 或者 backward
        perPageAvailable:	Array<number>	[5, 10, 20, 50, 100]	设置一页显示多少条数据下拉框可选条数。
        orderField:	string		设置用来确定位置的字段名，设置后新的顺序将被赋值到该字段中。
        hideQuickSaveBtn:	boolean	false	隐藏顶部快速保存提示
        autoJumpToTopOnPagerChange:	boolean	false	当切分页的时候，是否自动跳顶部。
        syncResponse2Query:	boolean	true	将返回数据同步到过滤器上。
        keepItemSelectionOnPageChange:	boolean	true	保留条目选择，默认分页、搜索后，用户选择条目会被清空，开启此选项后会保留用户选择，可以实现跨页面批量操作。
        labelTpl:	string		单条描述模板，keepItemSelectionOnPageChange设置为true后会把所有已选择条目列出来，此选项可以用来定制条目展示文案。
        maxKeepItemSelectionLength:	number	true	和keepItemSelectionOnPageChange搭配使用，限制最大勾选数。
        maxItemSelectionLength:	number	true	可单独使用限制当前页的最大勾选数，也可以和keepItemSelectionOnPageChange搭配使用达到和 maxKeepItemSelectionLength 一样的效果。
        headerToolbar:	Array	['bulkActions', 'pagination']	顶部工具栏配置
        footerToolbar:	Array	['statistics', 'pagination']	底部工具栏配置
        alwaysShowPagination:	boolean	false	是否总是显示分页
        affixHeader:	boolean	true	是否固定表头(table 下)
        affixFooter:	boolean	false	是否固定表格底部工具栏
        autoGenerateFilter:	Object | boolean		是否开启查询区域，开启后会根据列元素的 searchable 属性值，自动生成查询条件表单
        resetPageAfterAjaxItemAction:	boolean	false	单条数据 ajax 操作后是否重置页码为第一页
        autoFillHeight:	boolean 丨 {height: number}		内容区域自适应高度
        canAccessSuperData:	boolean	true	指定是否可以自动获取上层的数据并映射到表格行数据上，如果列也配置了该属性，则列的优先级更高
        matchFunc:	string	CRUDMatchFunc	自定义匹配函数, 当开启loadDataOnce时，会基于该函数计算的匹配结果进行过滤，主要用于处理列字段类型较为复杂或者字段值格式和后端返回不一致的场景	3.5.0
        parsePrimitiveQuery:	ParsePrimitiveQueryOptions	true	是否开启 Query 信息转换，开启后将会对 url 中的 Query 进行转换，默认开启，默认仅转化布尔值
    """

    def __init__(self,
                 mode: Literal["table", "cards", "list"] = "table",
                 title: str = "",
                 className: str = "",
                 api: Api = None,
                 deferApi: Api = None,
                 loadDataOnce: bool = False,
                 loadDataOnceFetchOnFilter: bool = False,
                 source: str = "",
                 filter: Form = None,
                 filterTogglable: Union[bool, Dict] = None,
                 filterDefaultVisible: bool = True,
                 initFetch: bool = True,
                 interval: Number = None,
                 silentPolling: bool = False,
                 stopAutoRefreshWhen: str = "",
                 stopAutoRefreshWhenModalIsOpen: bool = False,
                 syncLocation: bool = True,
                 draggable: bool = False,
                 resizable: bool = True,
                 itemDraggableOn: bool = False,
                 saveOrderApi: Api = None,
                 quickSaveApi: Api = None,
                 quickSaveItemApi: Api = None,
                 bulkActions: List[Action] = None,
                 messages: SchemaMessage = None,
                 primaryField: str = "id",
                 perPage: Number = None,
                 orderBy: str = "",
                 orderDir: OrderDir = OrderDir.none,
                 defaultParams: object = None,
                 pageField: str = "",
                 perPageField: str = "",
                 pageDirectionField: str = "",
                 perPageAvailable: List[Number] = None,
                 orderField: str = "",
                 hideQuickSaveBtn: bool = False,
                 autoJumpToTopOnPagerChange: bool = False,
                 syncResponse2Query: bool = True,
                 keepItemSelectionOnPageChange: bool = True,
                 labelTpl: str = "",
                 maxKeepItemSelectionLength: Number = None,
                 maxItemSelectionLength: Number = None,
                 headerToolbar: List[str] = None,
                 footerToolbar: List[str] = None,
                 alwaysShowPagination: bool = False,
                 affixHeader: bool = True,
                 affixFooter: bool = False,
                 autoGenerateFilter: any = None,
                 resetPageAfterAjaxItemAction: bool = False,
                 autoFillHeight: Union[bool, Dict] = None,
                 canAccessSuperData: bool = True,
                 matchFunc: str = "",
                 parsePrimitiveQuery: str = "",
                 **kwargs
                 ):
        super().__init__()
        self.type = "crud"
        self.mode: Literal["table", "cards", "list"] = mode
        self.title: str = title
        self.className: str = className
        self.api: Api = api
        self.deferApi: Api = deferApi
        self.loadDataOnce: bool = loadDataOnce
        self.loadDataOnceFetchOnFilter: bool = loadDataOnceFetchOnFilter
        self.source: str = source
        self.filter: Form = filter
        self.filterTogglable: Union[bool, Dict] = filterTogglable
        self.filterDefaultVisible: bool = filterDefaultVisible
        self.initFetch: bool = initFetch
        self.interval: Number = interval
        self.silentPolling: bool = silentPolling
        self.stopAutoRefreshWhen: str = stopAutoRefreshWhen
        self.stopAutoRefreshWhenModalIsOpen: bool = stopAutoRefreshWhenModalIsOpen
        self.syncLocation: bool = syncLocation
        self.draggable: bool = draggable
        self.resizable: bool = resizable
        self.itemDraggableOn: bool = itemDraggableOn
        self.saveOrderApi: Api = saveOrderApi
        self.quickSaveApi: Api = quickSaveApi
        self.quickSaveItemApi: Api = quickSaveItemApi
        self.bulkActions: List[Action] = bulkActions
        self.messages: SchemaMessage = messages
        self.primaryField: str = primaryField
        self.perPage: Number = perPage
        self.orderBy: str = orderBy
        self.orderDir: OrderDir = orderDir
        self.defaultParams: object = defaultParams
        self.pageField: str = pageField
        self.perPageField: str = perPageField
        self.pageDirectionField: str = pageDirectionField
        self.perPageAvailable: List[Number] = perPageAvailable
        self.orderField: str = orderField
        self.hideQuickSaveBtn: bool = hideQuickSaveBtn
        self.autoJumpToTopOnPagerChange: bool = autoJumpToTopOnPagerChange
        self.syncResponse2Query: bool = syncResponse2Query
        self.keepItemSelectionOnPageChange: bool = keepItemSelectionOnPageChange
        self.labelTpl: str = labelTpl
        self.maxKeepItemSelectionLength: Number = maxKeepItemSelectionLength
        self.maxItemSelectionLength: Number = maxItemSelectionLength
        self.headerToolbar: List[str] = headerToolbar
        self.footerToolbar: List[str] = footerToolbar
        self.alwaysShowPagination: bool = alwaysShowPagination
        self.affixHeader: bool = affixHeader
        self.affixFooter: bool = affixFooter
        self.autoGenerateFilter: any = autoGenerateFilter
        self.resetPageAfterAjaxItemAction: bool = resetPageAfterAjaxItemAction
        self.autoFillHeight: Union[bool, Dict] = autoFillHeight
        self.canAccessSuperData: bool = canAccessSuperData
        self.matchFunc: str = matchFunc
        self.parsePrimitiveQuery: str = parsePrimitiveQuery
        for _key, _value in kwargs.items():
            self.__dict__[_key] = _value


class Column(BaseSchema):
    def __init__(self,
                 label: str = "",
                 name: str = "",
                 width: Union[Number, str] = "",
                 remark: Remark = None,
                 fixed: Literal["left", "right", "none"] = "",
                 popOver: object = None,
                 copyable: Union[bool, Dict] = False,
                 style: Dict = None,
                 innerStyle: Dict = None,
                 align: Literal["left", "right"] = "",
                 **kwargs
                 ):
        super().__init__()
        self.label: str = label
        self.name: str = name
        self.width: Union[Number, str] = width
        self.remark: Remark = remark
        self.fixed: Literal["left", "right", "none"] = fixed
        self.popOver: object = popOver
        self.copyable: Union[bool, Dict] = copyable
        self.style: Dict = style
        self.innerStyle: Dict = innerStyle
        self.align: Literal["left", "right"] = align
        for _key, _value in kwargs.items():
            self.__dict__[_key] = _value


class Table(BaseSchema):
    def __init__(self,
                 title: str = "",
                 source: SchemaExpression = "${items}",
                 deferApi: Api = None,
                 affixHeader: bool = True,
                 affixFooter: bool = False,
                 columnsTogglable: Union[Literal["auto"], bool] = "auto",
                 placeholder: str = "",
                 className: str = "",
                 tableClassName: str = "",
                 headerClassName: str = "",
                 footerClassName: str = "",
                 toolbarClassName: str = "",
                 columns: List[Column] = None,
                 combineNum: Number = None,
                 itemActions: List[Action] = None,
                 itemCheckableOn: SchemaExpression = "",
                 itemDraggableOn: SchemaExpression = "",
                 checkOnItemClick: bool = False,
                 rowClassName: str = "",
                 rowClassNameExpr: str = "",
                 prefixRow: List = None,
                 affixRow: List = None,
                 itemBadge: Badge = None,
                 autoFillHeight: Union[bool, Dict] = None,
                 resizable: bool = False,
                 selectable: bool = False,
                 multiple: bool = False,
                 lazyRenderAfter: Number = None,
                 tableLayout: Literal["auto", "fixed"] = "auto",
                 onEvent: OnEvent = None,
                 **kwargs
                 ):
        super().__init__()
        self.type = "table"
        self.title: str = title
        self.source: str = source
        self.deferApi: Api = deferApi
        self.affixHeader: bool = affixHeader
        self.affixFooter: bool = affixFooter
        self.columnsTogglable: Union[Literal["auto"], bool] = columnsTogglable
        self.placeholder: str = placeholder
        self.className: str = className
        self.tableClassName: str = tableClassName
        self.headerClassName: str = headerClassName
        self.footerClassName: str = footerClassName
        self.toolbarClassName: str = toolbarClassName
        self.columns: List[Column] = columns
        self.combineNum: Number = combineNum
        self.itemActions: List[Action] = itemActions
        self.itemCheckableOn: SchemaExpression = itemCheckableOn
        self.itemDraggableOn: SchemaExpression = itemDraggableOn
        self.checkOnItemClick: bool = checkOnItemClick
        self.rowClassName: str = rowClassName
        self.rowClassNameExpr: str = rowClassNameExpr
        self.prefixRow: List = prefixRow
        self.affixRow: List = affixRow
        self.itemBadge: Badge = itemBadge
        self.autoFillHeight: Union[bool, Dict] = autoFillHeight
        self.resizable: bool = resizable
        self.selectable: bool = selectable
        self.multiple: bool = multiple
        self.lazyRenderAfter: Number = lazyRenderAfter
        self.tableLayout: Literal["auto", "fixed"] = tableLayout
        self.onEvent: OnEvent = onEvent
        for _key, _value in kwargs.items():
            self.__dict__[_key] = _value


class Status(BaseSchema):
    """
     状态展示控件。
    """

    def __init__(
            self,
            placeholder: str = None,
            className: str = None,
            map: Dict[str, str] = None,
            labelMap: Dict[str, str] = None,
            source: Dict[str, str] = None,
            **kwargs,
    ):
        super().__init__()
        self.type: str = "status"
        # 占位符
        self.placeholder: str = placeholder
        # 外层 Dom 的 CSS 类名
        self.className: str = className
        # 状态图标映射关系
        self.map: Dict[str, str] = map
        # 文字映射关系
        self.labelMap: Dict[str, str] = labelMap
        # 自定义映射状态，支持数据映射
        self.source: Dict[str, str] = source

        for key, value in kwargs.items():
            self.__dict__[key] = value


class Image(BaseSchema):
    def __init__(
            self,
            defaultImage: SchemaUrlPath = None,
            title: SchemaTpl = None,
            name: str = None,
            imageCaption: SchemaTpl = None,
            src: SchemaUrlPath = None,
            originalSrc: SchemaUrlPath = None,
            enlargeAble: bool = None,
            enlargeWithGallary: bool = None,
            alt: str = None,
            height: Number = None,
            width: Number = None,
            className: SchemaClassName = None,
            innerClassName: SchemaClassName = None,
            imageClassName: SchemaClassName = None,
            thumbClassName: SchemaClassName = None,
            imageGallaryClassName: SchemaClassName = None,
            caption: SchemaTpl = None,
            imageMode: Literal["thumb", "original"] = None,
            thumbMode: Literal['w-full', 'h-full', 'contain', 'cover'] = None,
            thumbRatio: Literal['1:1', '4:3', '16:9'] = None,
            href: SchemaTpl = None,
            blank: bool = None,
            htmlTarget: str = None,
            showToolbar: bool = None,
            toolbarActions: List[Dict[str, object]] = None,
            maxScale: Number = None,
            minScale: Number = None,
            **kwargs,
    ):
        super().__init__()
        self.type: str = "image"
        # 默认图片地址
        self.defaultImage: SchemaUrlPath = defaultImage
        # 图片标题
        self.title: SchemaTpl = title
        # 关联字段名，也可以直接配置 src
        self.name: str = name
        # 图片描述信息
        self.imageCaption: SchemaTpl = imageCaption
        # 图片地址，如果配置了 name，这个属性不用配置。
        self.src: SchemaUrlPath = src
        # 大图地址，不设置用 src
        self.originalSrc: SchemaUrlPath = originalSrc
        # 是否启动放大功能。
        self.enlargeAble: bool = enlargeAble
        # 放大时是否显示图片集
        self.enlargeWithGallary: bool = enlargeWithGallary
        # 图片无法显示时的替换文本
        self.alt: str = alt
        # 高度
        self.height: Number = height
        # 宽度
        self.width: Number = width
        # 外层 css 类名
        self.className: SchemaClassName = className
        # 组件内层 css 类名
        self.innerClassName: SchemaClassName = innerClassName
        # 图片 css 类名
        self.imageClassName: SchemaClassName = imageClassName
        # 图片缩略图外层 css 类名
        self.thumbClassName: SchemaClassName = thumbClassName
        # 放大详情图 CSS 类名
        self.imageGallaryClassName: SchemaClassName = imageGallaryClassName
        # 图片说明文字
        self.caption: SchemaTpl = caption
        # 图片展示模式，默认为缩略图模式、可以配置成原图模式
        self.imageMode: Literal["thumb", "original"] = imageMode
        # 预览图模式
        self.thumbMode: Literal['w-full', 'h-full', 'contain', 'cover'] = thumbMode
        # 预览图比率
        self.thumbRatio: Literal['1:1', '4:3', '16:9'] = thumbRatio
        # 链接地址
        self.href: SchemaTpl = href
        # 是否新窗口打开
        self.blank: bool = blank
        # 链接的 target
        self.htmlTarget: str = htmlTarget
        # 是否展示图片工具栏
        self.showToolbar: bool = showToolbar
        # 图片工具栏，支持旋转，缩放，默认操作全部开启
        self.toolbarActions: List[Dict[str, object]] = toolbarActions
        # 执行调整图片比例动作时的最大百分比
        self.maxScale: Number = maxScale
        # 执行调整图片比例动作时的最小百分比
        self.minScale: Number = minScale

        for key, value in kwargs.items():
            self.__dict__[key] = value


class StaticImage(BaseSchema):
    def __init__(
            self,
            label: str = None,
            defaultImage: SchemaUrlPath = None,
            title: SchemaTpl = None,
            name: str = None,
            imageCaption: SchemaTpl = None,
            src: SchemaUrlPath = None,
            originalSrc: SchemaUrlPath = None,
            enlargeAble: bool = None,
            enlargeWithGallary: bool = None,
            alt: str = None,
            height: Number = None,
            width: Number = None,
            className: SchemaClassName = None,
            innerClassName: SchemaClassName = None,
            imageClassName: SchemaClassName = None,
            thumbClassName: SchemaClassName = None,
            imageGallaryClassName: SchemaClassName = None,
            caption: SchemaTpl = None,
            imageMode: Literal["thumb", "original"] = None,
            thumbMode: Literal['w-full', 'h-full', 'contain', 'cover'] = None,
            thumbRatio: Literal['1:1', '4:3', '16:9'] = None,
            href: SchemaTpl = None,
            blank: bool = None,
            htmlTarget: str = None,
            showToolbar: bool = None,
            toolbarActions: List[Dict[str, object]] = None,
            maxScale: Number = None,
            minScale: Number = None,
            **kwargs,
    ):
        super().__init__()
        self.type: str = "static-image"
        self.label: str = label
        # 默认图片地址
        self.defaultImage: SchemaUrlPath = defaultImage
        # 图片标题
        self.title: SchemaTpl = title
        # 关联字段名，也可以直接配置 src
        self.name: str = name
        # 图片描述信息
        self.imageCaption: SchemaTpl = imageCaption
        # 图片地址，如果配置了 name，这个属性不用配置。
        self.src: SchemaUrlPath = src
        # 大图地址，不设置用 src
        self.originalSrc: SchemaUrlPath = originalSrc
        # 是否启动放大功能。
        self.enlargeAble: bool = enlargeAble
        # 放大时是否显示图片集
        self.enlargeWithGallary: bool = enlargeWithGallary
        # 图片无法显示时的替换文本
        self.alt: str = alt
        # 高度
        self.height: Number = height
        # 宽度
        self.width: Number = width
        # 外层 css 类名
        self.className: SchemaClassName = className
        # 组件内层 css 类名
        self.innerClassName: SchemaClassName = innerClassName
        # 图片 css 类名
        self.imageClassName: SchemaClassName = imageClassName
        # 图片缩略图外层 css 类名
        self.thumbClassName: SchemaClassName = thumbClassName
        # 放大详情图 CSS 类名
        self.imageGallaryClassName: SchemaClassName = imageGallaryClassName
        # 图片说明文字
        self.caption: SchemaTpl = caption
        # 图片展示模式，默认为缩略图模式、可以配置成原图模式
        self.imageMode: Literal["thumb", "original"] = imageMode
        # 预览图模式
        self.thumbMode: Literal['w-full', 'h-full', 'contain', 'cover'] = thumbMode
        # 预览图比率
        self.thumbRatio: Literal['1:1', '4:3', '16:9'] = thumbRatio
        # 链接地址
        self.href: SchemaTpl = href
        # 是否新窗口打开
        self.blank: bool = blank
        # 链接的 target
        self.htmlTarget: str = htmlTarget
        # 是否展示图片工具栏
        self.showToolbar: bool = showToolbar
        # 图片工具栏，支持旋转，缩放，默认操作全部开启
        self.toolbarActions: List[Dict[str, object]] = toolbarActions
        # 执行调整图片比例动作时的最大百分比
        self.maxScale: Number = maxScale
        # 执行调整图片比例动作时的最小百分比
        self.minScale: Number = minScale

        for key, value in kwargs.items():
            self.__dict__[key] = value


class ScheduleItem(Renderable):
    def __init__(
            self,
            startTime: str = None,
            endTime: str = None,
            content: object = None,
            className: str = None,
            **kwargs,
    ):
        super().__init__()
        self.startTime: str = startTime
        self.endTime: str = endTime
        self.content: object = content
        self.className: str = className

        for key, value in kwargs.items():
            self.__dict__[key] = value


class Calendar(BaseSchema):
    """
     Calendar 日历日程
    """

    def __init__(
            self,
            schedules: Union[List[ScheduleItem], str] = None,
            scheduleClassNames: List[str] = None,
            scheduleAction: SchemaNode = None,
            largeMode: bool = None,
            todayActiveStyle: Dict[str, str] = None,
            **kwargs,
    ):
        super().__init__()
        self.type: str = "calendar"
        # 日程
        self.schedules: Union[List[ScheduleItem], str] = schedules
        # 日程显示颜色自定义
        self.scheduleClassNames: List[str] = scheduleClassNames
        # 日程点击展示
        self.scheduleAction: SchemaNode = scheduleAction
        # 是否开启放大模式
        self.largeMode: bool = largeMode
        # 今日激活时的自定义样式
        self.todayActiveStyle: Dict[str, str] = todayActiveStyle

        for key, value in kwargs.items():
            self.__dict__[key] = value


class CarouselItem(Renderable):
    def __init__(
            self,
            image: str = None,
            href: str = None,
            imageClassName: str = None,
            title: str = None,
            titleClassName: str = None,
            description: str = None,
            descriptionClassName: str = None,
            html: str = None,
            **kwargs,
    ):
        super().__init__()
        # 图片链接
        self.image: str = image
        # 图片打开网址的链接
        self.href: str = href
        # 图片类名
        self.imageClassName: str = imageClassName
        # 图片标题
        self.title: str = title
        # 图片标题类名
        self.titleClassName: str = titleClassName
        # 图片描述
        self.description: str = description
        # 图片描述类名
        self.descriptionClassName: str = descriptionClassName
        # HTML 自定义，同Tpl一致
        self.html: str = html

        for key, value in kwargs.items():
            self.__dict__[key] = value


class Carousel(BaseSchema):
    """
    Carousel 轮播图渲染器。
    """
    def __init__(
            self,
            auto: bool = None,
            className: str = None,
            interval: Union[Number, str] = None,
            duration: Number = None,
            width: Number = None,
            height: Number = None,
            controlsTheme: Theme = None,
            placeholder: str = None,
            controls: List[Literal['dots', 'arrows']] = None,
            animation: Literal['fade', 'slide'] = None,
            itemSchema: SchemaCollection = None,
            name: SchemaName = None,
            thumbMode: Literal['contain', 'cover'] = None,
            options: List[CarouselItem] = None,
            alwaysShowArrow: bool = None,
            multiple: Dict[Literal['count'], Number] = None,
            icons: Dict[Literal['prev', 'next'], SchemaCollection] = None,
            **kwargs,
    ):
        super().__init__()
        self.type = "carousel"
        # 外层 Dom 的类名
        self.className: str = className
        # 是否自动播放
        self.auto: bool = auto
        # 轮播间隔时间
        self.interval: Union[Number, str] = interval
        # 切换动画时长（ms）
        self.duration: Number = duration
        # 设置宽度
        self.width: Number = width
        # 设置高度
        self.height: Number = height
        # 左右箭头、底部圆点索引颜色，默认light，另有dark模式
        self.controlsTheme: Theme = controlsTheme
        # 占位
        self.placeholder: str = placeholder
        # 显示左右箭头、底部圆点索引
        self.controls: List[Literal['dots', 'arrows']] = controls
        # 切换动画效果，默认fade，另有slide模式
        self.animation: Literal['fade', 'slide'] = animation
        # 配置单条呈现模板
        self.itemSchema: SchemaCollection = itemSchema
        self.name: SchemaName = name
        # 图片默认缩放模式
        self.thumbMode: Literal['contain', 'cover'] = thumbMode
        # 轮播面板数据
        self.options: List[CarouselItem] = options
        # 是否一直显示箭头，为 false 时鼠标 hover 才会显示
        self.alwaysShowArrow: bool = alwaysShowArrow
        # 多图模式配置项
        self.multiple: Dict[Literal['count'], Number] = multiple
        # 自定义箭头图标
        self.icons: Dict[Literal['prev', 'next'], SchemaCollection] = icons

        for key, value in kwargs.items():
            self.__dict__[key] = value


class Chart(BaseSchema):
    """
    Chart 图表渲染器
    """
    def __init__(
            self,
            name: SchemaName = None,
            className: str = None,
            body: SchemaNode = None,
            api: SchemaApi = None,
            source: str = None,
            interval: Number = None,
            config: object = None,
            style: Dict[str, object] = None,
            width: Union[Number, str] = None,
            height: Union[Number, str] = None,
            replaceChartOption: bool = None,
            trackExpression: str = None,
            dataFilter: SchemaFunction = None,
            mapURL: SchemaApi = None,
            mapName: str = None,
            loadBaiduMap: bool = None,
            **kwargs,
    ):
        super().__init__()
        self.type = "chart"
        name: SchemaName = name
        # 外层 Dom 的类名
        self.className: str = className
        # 内容容器
        self.body: SchemaNode = body
        # 配置项接口地址
        self.api: SchemaApi = api
        # 通过数据映射获取数据链中变量值作为配置
        self.source: str = source
        # 刷新时间(最小 1000)
        self.interval: Number = interval
        # 设置 eschars 的配置项,当为string的时候可以设置 function 等配置项
        self.config: object = config
        # 设置根元素的 style
        self.style: Dict[str, object] = style
        # 设置根元素的宽度
        self.width: Union[Number, str] = width
        # 设置根元素的高度
        self.height: Union[Number, str] = height
        # 每次更新是完全覆盖配置项还是追加？
        self.replaceChartOption: bool = replaceChartOption
        # 当这个表达式的值有变化时更新图表
        self.trackExpression: str = trackExpression
        # 自定义 echart config 转换，函数签名：function(config, echarts, data) {return config;} 配置时直接写函数体。其中 config 是当前 echart 配置，echarts 就是 echarts 对象，data 为上下文数据。
        self.dataFilter: SchemaFunction = dataFilter
        # 获取 geo json 文件的地址
        self.mapURL: SchemaApi = mapURL
        # 地图名称
        self.mapName: str = mapName
        # 加载百度地图
        self.loadBaiduMap: bool = loadBaiduMap

        for key, value in kwargs.items():
            self.__dict__[key] = value